﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using System.Configuration;
using log4net;

namespace LanguageDetector.TrainerConsole
{
    internal class ProcessFolder
    {
        #region static vars & ctor

        readonly static List<string> EXTENSIONS = new List<string> {
            "txt",
            "xml",
            "html",
            "htm",
            "rss",
            "sgm",
            "sgml",
        };
        static ProcessFolder()
        {
            var arr = (ConfigurationManager.AppSettings["ProcessExtensionCSV"] ?? "").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (arr != null && arr.Length > 0)
            {
                EXTENSIONS.Clear();
                EXTENSIONS.AddRange(arr);
            }
        }

        #endregion

        #region vars & ctor

        ILog logger = LogManager.GetLogger(typeof(ProcessFolder));
        List<string> _files = new List<string>();
        TrainerLogic _logic;
        string _path;
        bool _recursive;
        ConsoleBuilder _console;

        public ProcessFolder(TrainerLogic logic, string path, bool recursive, ConsoleBuilder console)
        {
            _logic = logic;
            _path = path;
            _recursive = recursive;
            _console = console;
        }

        #endregion

        int _doneCount = 0;
        public void Run()
        {
            CollectFiles(_path);
            if (_files.Count > 0)
                _files.RemoveAll(f => !ProcessExtension(f));
            if (_files.Count > 0)
            {
                _logic.Done += new Action<TrainerLogic, TrainerDoneEventArgs>(_logic_Done);
                _doneCount = 0;
                _console.AppendLine("Found {0} files for processing.", _files.Count);
                for (var i = 0; i < _files.Count; i++)
                {
                    var fpath = _files[i];
                    var content = File.ReadAllText(fpath);
                    _console.AppendLine("\tJob\t{0}\t> {1} Starting...", content.GetHashCode(), fpath.Substring(fpath.LastIndexOf('/') + 1));
                    ThreadPool.QueueUserWorkItem(_logic.Run, content);
                }
                while (_doneCount < _files.Count)
                {
                    Thread.Sleep(100);
                }
                _logic.Done -= new Action<TrainerLogic, TrainerDoneEventArgs>(_logic_Done);
            }
            else
                _console.AppendLine("No file where found for processing.");
        }

        void _logic_Done(TrainerLogic caller, TrainerDoneEventArgs args)
        {
            _doneCount++;
            _console.AppendLine("\tJob\t{0}\t> BiGrams {1}, Took: {2}", 
                args.OriginalInput.GetHashCode(), _logic.Result.Count, args.Duration);
        }

        void CollectFiles(string path)
        {
            if (Directory.Exists(path))
            {
                path = path.Replace('\\', '/');
                if (path[path.Length - 1] != '/')
                    path += "/";
                if (_recursive)
                {
                    var subs = Directory.GetDirectories(path);
                    if (!subs.IsNullOrEmpty())
                    {
                        for (var i = 0; i < subs.Length; i++)
                        {
                            CollectFiles(subs[i]);
                        }
                    }
                }
                _console.AppendLine(path);
                var files = Directory.GetFiles(path);
                if (files != null && files.Length > 0)
                    _files.AddRange(files);
            }
            else
                _console.AppendLine("Path does not exists: {0}", path);
        }

        public static bool ProcessExtension(string fpath)
        {
            var b = false;
            var ix = fpath.LastIndexOf('.');
            if (ix > 0 && ix < fpath.Length - 2)
            {
                var l = fpath.Substring(ix + 1);
                b = EXTENSIONS.Contains(l.ToLower());
            }
            return b;
        }
    }
}
